allocator原理介绍
考虑到小型区域可能造成内存破碎问题,SGI STL设计了双层级配置器,第一层配置器直接使用malloc()和free(),第二层配置器则视情况采用不同的策略:当配置区块超过128bytes时,调用第一层级配置器,当配置区块小于128bytes时,采用复杂的memory pool方式。
第一级配置器__malloc_alloc_template
|
|
上面代码看起来复杂,其实流程是这样的:
- 通过allocate()申请内存,通过deallocate()来释放内存,通过reallocate()重新分配内存
- 当allocate()或reallocate()分配内存不足时会调用oom_malloc()或oom_remalloc()来处理
- 当oom_malloc() 或 oom_remalloc()还是没能分配到申请的内存时,会转如下两步中的一步:
- 调用用户自定义的内存分配不足处理函数(这个函数通过set_malloc_handler() 来设定),然后继续申请内存
- 如果用户未定义内存分配不足处理函数,程序就会抛出bad_alloc异常或利用exit(1)终止程序
第二级配置器__default_alloc_template
当申请的内存大于 128 bytes时就调用第一层配置器。当申请的内存小于 128bytes时才会调用第二层配置器。第二层配置器如何维护128bytes以下内存的配置呢? SGI 第二层配置器定义了一个 free-lists,这个free-list是一个数组,如下图:
这个数组的元素都是指针,用来指向16个链表的表头,这16个链表上面挂的都是可以用的内存块。只是不同链表中元素的内存块大小不一样,16个链表上分别挂着大小为8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小额区块,图如下:
下面我们看下allocate()代码:
|
|
其中有两个函数我来提一下,一个是ROUND_UP(),这个是将要申请的内存字节数上调为8的倍数。因为我们free-lists中挂的内存块大小都是8的倍数嘛,这样才知道应该去找哪一个链表。另一个就是refill()。这个是在没找到可用的free list的时候调用,准备填充free lists。意思是:参考上图,假设我现在要申请大小为 56bytes 的内存空间,那么就会到free lists 的第 7 个元素所指的链表上去找。如果此时 #7元素所指的链表为空怎么办?这个时候就要调用refill()函数向内存池申请N(一般为20个)个大小为56bytes的内存区块,然后挂到 #7 所指的链表上。这样,申请者就可以得到内存块了。当然,这里为了避免复杂,误导读者我就不讨论refill()函数了。allocate()过程图如下:
下面再看下deallocate()的代码:
|
|
说明
本文转载自文章浅析STL allocator。